package com.factory.server.dao;


import com.factory.server.bo.AbstractBusinessObject;
import com.googlecode.gentyref.GenericTypeReflector;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;


import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import java.util.List;

/**
 * Implements (using Hibernate) AbstractSpecificDAOIface operations
 *
 * @author Pavel Micka (mickapa1@fel.cvut.cz)
 * @param <ENTITY> business entity which is this dao designed for
 *
 */
public abstract class AbstractSpecificDao<ENTITY extends AbstractBusinessObject> implements SpecificDAOIface<ENTITY> {

    protected EntityManagerFactory entityManagerfactory;
    protected Class<ENTITY> clazz;
    protected GenericDAOIface genericDAO;
    private DAODispatcherIface genericDAODispatcher;

    @SuppressWarnings({"OverridableMethodCallInConstructor", "LeakingThisInConstructor"})
    public AbstractSpecificDao() {
        setClazz();
    }

    protected EntityManager getEntityManager() {
        throw new UnsupportedOperationException("Not implemented yet.");
    }

    /**
     * Returns all instances of class
     *
     * @return all instances of class which is specified using setClass method ordered by id ascendently
     */
    @SuppressWarnings("unchecked")
    public List<ENTITY> getAll() {
        return genericDAO.getAll(clazz);
    }

    /**
     * Returns all instances of class ordered by specified property
     *
     * @param property which specifies the ordering of resultset
     * @return instances of class ordered by property
     */
    @SuppressWarnings("unchecked")
    public List<ENTITY> getAllOrderedDesc(String property) {
        return genericDAO.getAllOrderedDesc(property, clazz);
    }

    /**
     * Vrati vsechny objekty serazene vzestupne dle dane property
     *
     * @param property
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<ENTITY> getAllOrderedAsc(String property) {
        return genericDAO.getAllOrderedAsc(property, clazz);
    }

    /**
     * Vrati objekty dane tridy, jejichz property se rovna objektu predanemu v
     * parametru, serazene dle id sestupne
     *
     * @param property property, kterou porovnavame
     * @param value hodnota, se kterou porovnavame
     * @return vsechny vyhovujici zaznamy
     */
    @SuppressWarnings("unchecked")
    public List<ENTITY> getByProperty(String property, Object value) {
        return genericDAO.getByProperty(property, value, clazz);
    }

    /**
     * Smaze objekt dle daneho ID
     *
     * @param id id objektu je smazani
     */
    public void removeById(long id) {
        genericDAO.removeById(id, clazz);
    }

    /**
     * Deletes specified entity
     *
     * @param entity entity to be deleted
     */
    public void remove(ENTITY entity) {
        genericDAO.remove(entity);
    }

    /**
     * Returns object (using get method) of class using ID as lookup key
     *
     * @param id id of the object to be returned
     * @return objekt identifikovany id, @null pokud neexistuje
     */
    @SuppressWarnings("unchecked")
    public ENTITY getById(long id) {
        return genericDAO.getById(id, clazz);
    }

    @SuppressWarnings("unchecked")
    public ENTITY loadById(long id) {
        return genericDAO.loadById(id, clazz);
    }

    public ENTITY saveOrUpdate(ENTITY entity) {
        return genericDAO.saveOrUpdate(entity);
    }

    public ENTITY getByPropertyUnique(String property, Object value) {
        return genericDAO.getByPropertyUnique(property, value, clazz);
    }

    public Long getCount() {
        return genericDAO.getCount(clazz);
    }

    public List<ENTITY> getPage(int from, int maxResults) {
        return genericDAO.getPage(from, maxResults, clazz);
    }

    public List<ENTITY> getPage(int first, int rows, String sortBy, boolean ascending) {
        return genericDAO.getPage(first, rows, sortBy, ascending, clazz);
    }

    public Class getClazz(){
        return clazz;
    }
    
    protected void setClazz() {
        Type baseType = GenericTypeReflector.getExactSuperType(this.getClass(), SpecificDAOIface.class);

        if (baseType instanceof Class<?>) {
            throw new IllegalArgumentException("Type parameter must be set in order to perform DB queries.");
        } else {
            ParameterizedType pBaseType = (ParameterizedType) baseType;
            assert pBaseType.getRawType() == SpecificDAOIface.class; // always true
            clazz = (Class<ENTITY>) pBaseType.getActualTypeArguments()[0];
        }
    }
    
}
